package com.ittao.taoaicodemother.manage.storage.service.impl;

import com.ittao.taoaicodemother.manage.storage.service.TempDirectoryService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 临时目录服务实现类
 * 提供临时目录管理功能，包括清理、调度清理和批量删除
 * 针对2核2G服务器优化，保守的并行删除策略
 */
@Slf4j
@Service
public class TempDirectoryServiceImpl implements TempDirectoryService {

    /**
     * 是否启用并行删除优化
     * 针对2核2G服务器配置，默认关闭以节省资源
     */
    private final boolean parallelDeleteEnabled = false;

    /**
     * 并行删除的文件数量阈值
     * 针对2核2G服务器配置，设置较高阈值
     */
    private final int parallelDeleteThreshold = 500;

    /**
     * 并行删除线程池大小
     * 针对2核2G服务器配置，固定为2个线程
     */
    private final int threadPoolSize = 2;

    /**
     * 并行删除超时时间（秒）
     * 针对2核2G服务器配置，设置较长超时时间
     */
    private final int deleteTimeoutSeconds = 60;

    /**
     * 清理临时文件（内部方法）
     *
     * @param tempFilePath 临时文件路径
     */
    private void cleanup(String tempFilePath) {
        if (tempFilePath == null || tempFilePath.trim().isEmpty()) {
            log.warn("临时文件路径为空，跳过清理");
            return;
        }

        try {
            Path path = Paths.get(tempFilePath);

            if (!Files.exists(path)) {
                log.debug("临时文件/目录不存在，无需清理: {}", tempFilePath);
                return;
            }

            if (Files.isDirectory(path)) {
                // 递归删除目录及其内容
                deleteDirectoryRecursively(path);
                log.info("临时目录清理完成: {}", tempFilePath);
            } else {
                // 删除单个文件
                Files.delete(path);
                log.info("临时文件清理完成: {}", tempFilePath);
            }

        } catch (IOException e) {
            log.error("清理临时文件/目录失败: {}, 错误信息: {}", tempFilePath, e.getMessage(), e);
        } catch (Exception e) {
            log.error("清理临时文件/目录时发生未知错误: {}, 错误信息: {}", tempFilePath, e.getMessage(), e);
        }
    }

    @Override
    public void cleanupTempDirectory(String tempDirPath) {
        log.debug("开始清理临时目录: {}", tempDirPath);
        cleanup(tempDirPath);
    }

    @Override
    public int batchDeleteDirectories(List<Path> directoriesToDelete) {
        if (directoriesToDelete == null || directoriesToDelete.isEmpty()) {
            log.debug("目录路径列表为空，无需批量删除");
            return 0;
        }

        int successCount = 0;
        int totalCount = directoriesToDelete.size();

        log.info("开始批量删除目录，总数: {}", totalCount);

        for (Path directoryPath : directoriesToDelete) {
            try {
                if (directoryPath == null) {
                    log.warn("跳过空的目录路径");
                    continue;
                }

                if (!Files.exists(directoryPath)) {
                    log.debug("目录不存在，跳过: {}", directoryPath);
                    successCount++; // 不存在也算成功
                    continue;
                }

                if (!Files.isDirectory(directoryPath)) {
                    log.warn("路径不是目录，跳过: {}", directoryPath);
                    continue;
                }

                // 删除目录及其内容
                deleteDirectoryRecursively(directoryPath);
                successCount++;
                log.debug("目录删除成功: {}", directoryPath);

            } catch (IOException e) {
                log.error("删除目录失败: {}, IO错误: {}", directoryPath, e.getMessage());
            } catch (Exception e) {
                log.error("删除目录时发生未知错误: {}, 错误信息: {}", directoryPath, e.getMessage(), e);
            }
        }

        log.info("批量删除目录完成: 成功 {}/{}", successCount, totalCount);
        return successCount;
    }

    /**
     * 递归删除目录及其所有内容
     * 使用安全的NIO删除方式，支持并行优化
     *
     * @param directory 要删除的目录路径
     * @throws IOException 如果删除过程中发生IO错误
     */
    private void deleteDirectoryRecursively(Path directory) throws IOException {
        if (!Files.exists(directory)) {
            return;
        }

        // 智能选择删除策略
        if (parallelDeleteEnabled && shouldUseParallelDelete(directory)) {
            log.debug("使用并行删除策略: {}", directory);
            deleteWithParallelNIO(directory);
        } else {
            log.debug("使用标准删除策略: {}", directory);
            deleteWithOptimizedNIO(directory);
        }
    }

    /**
     * 判断是否应该使用并行删除
     * 基于文件数量和配置决定
     */
    private boolean shouldUseParallelDelete(Path directory) {
        try {
            AtomicInteger fileCount = new AtomicInteger(0);
            Files.walkFileTree(directory, new SimpleFileVisitor<Path>() {
                @Override
                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
                    fileCount.incrementAndGet();
                    // 如果文件数量超过阈值，提前返回
                    if (fileCount.get() > parallelDeleteThreshold) {
                        return FileVisitResult.TERMINATE;
                    }
                    return FileVisitResult.CONTINUE;
                }
            });
            
            boolean shouldUseParallel = fileCount.get() >= parallelDeleteThreshold;
            log.debug("目录 {} 包含 {} 个文件，{}", directory, fileCount.get(), 
                     shouldUseParallel ? "使用并行删除" : "使用标准删除");
            return shouldUseParallel;
            
        } catch (IOException e) {
            log.warn("无法统计文件数量，使用标准删除: {}", directory);
            return false;
        }
    }

    /**
     * 使用并行NIO方式删除目录
     * 提升大目录删除性能
     */
    private void deleteWithParallelNIO(Path directory) throws IOException {
        long startTime = System.currentTimeMillis();
        AtomicInteger deletedFiles = new AtomicInteger(0);
        AtomicInteger deletedDirs = new AtomicInteger(0);
        AtomicInteger failedCount = new AtomicInteger(0);

        ExecutorService executor = Executors.newFixedThreadPool(threadPoolSize);
        
        try {
            // 收集所有文件和目录
            Files.walkFileTree(directory, new SimpleFileVisitor<Path>() {
                @Override
                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
                    // 异步删除文件
                    CompletableFuture.runAsync(() -> {
                        try {
                            Files.delete(file);
                            deletedFiles.incrementAndGet();
                        } catch (IOException e) {
                            failedCount.incrementAndGet();
                            log.warn("并行删除文件失败: {}, 错误: {}", file, e.getMessage());
                        }
                    }, executor);
                    return FileVisitResult.CONTINUE;
                }

                @Override
                public FileVisitResult postVisitDirectory(Path dir, IOException exc) {
                    // 目录需要在文件删除后再删除，使用延迟删除
                    CompletableFuture.runAsync(() -> {
                        try {
                            // 等待一小段时间确保文件删除完成
                            Thread.sleep(10);
                            Files.delete(dir);
                            deletedDirs.incrementAndGet();
                        } catch (IOException e) {
                            failedCount.incrementAndGet();
                            log.warn("并行删除目录失败: {}, 错误: {}", dir, e.getMessage());
                        } catch (InterruptedException e) {
                            Thread.currentThread().interrupt();
                            log.warn("并行删除被中断: {}", dir);
                        }
                    }, executor);
                    return FileVisitResult.CONTINUE;
                }
            });

            // 等待所有删除任务完成
            executor.shutdown();
            if (!executor.awaitTermination(deleteTimeoutSeconds, TimeUnit.SECONDS)) {
                log.warn("并行删除超时，强制关闭线程池: {}", directory);
                executor.shutdownNow();
            }

            long duration = System.currentTimeMillis() - startTime;
            log.info("并行删除完成: {} - 文件: {}, 目录: {}, 失败: {}, 耗时: {}ms", 
                    directory, deletedFiles.get(), deletedDirs.get(), failedCount.get(), duration);

        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            log.error("并行删除被中断: {}", directory);
            throw new IOException("并行删除被中断", e);
        } finally {
            if (!executor.isShutdown()) {
                executor.shutdownNow();
            }
        }
    }

    /**
     * 使用优化的NIO方式删除目录
     * 采用深度优先遍历，先删除文件再删除目录
     * 增强错误处理和性能监控
     */
    private void deleteWithOptimizedNIO(Path directory) throws IOException {
        long startTime = System.currentTimeMillis();
        AtomicInteger deletedFiles = new AtomicInteger(0);
        AtomicInteger deletedDirs = new AtomicInteger(0);
        AtomicInteger failedCount = new AtomicInteger(0);

        Files.walkFileTree(directory, new SimpleFileVisitor<Path>() {
            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                try {
                    Files.delete(file);
                    deletedFiles.incrementAndGet();
                } catch (IOException e) {
                    failedCount.incrementAndGet();
                    log.warn("删除文件失败: {}, 错误: {}", file, e.getMessage());
                    // 继续删除其他文件，不中断整个删除过程
                }
                return FileVisitResult.CONTINUE;
            }

            @Override
            public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
                try {
                    Files.delete(dir);
                    deletedDirs.incrementAndGet();
                } catch (IOException e) {
                    failedCount.incrementAndGet();
                    log.warn("删除目录失败: {}, 错误: {}", dir, e.getMessage());
                    // 继续删除其他目录，不中断整个删除过程
                }
                return FileVisitResult.CONTINUE;
            }
        });

        long duration = System.currentTimeMillis() - startTime;
        log.info("标准删除完成: {} - 文件: {}, 目录: {}, 失败: {}, 耗时: {}ms", 
                directory, deletedFiles.get(), deletedDirs.get(), failedCount.get(), duration);
    }
}